/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package persistencia.dao;

import persistencia.session.hibernateSessionFactory;
import java.util.List;
import javax.swing.JOptionPane;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.QueryException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

/**
 *
 * @author Maycon Fernando Silva Brito @email mayconfsbrito@gmail.com
 */
public class AbstractDAO {

    protected static Session sessao = null;
    protected static Transaction transacao = null;

    public static synchronized Session getSessao(){
        if(sessao != null && sessao.isOpen()) {
            fechaSessao();
            sessao = hibernateSessionFactory.getSession();
            
        } else {
            sessao = hibernateSessionFactory.getSession();
        }
        return sessao;
    }
    
    /**
     * Inicializa a sessao para efetuar as transacoes no banco de dados
     */
    protected static final void inicializaSessao() {
        sessao = getSessao();
    }

    /**
     * Fecha a sessao caso ela esteja aberta
     */
    public static boolean fechaSessao() {
        if (sessao.isOpen()) {
            sessao.flush();
            sessao.close();

            return true;
        }

        return false;
    }

    /**
     * Cadastra um unico objeto no banco de dados
     *
     * @param obj - Objetto a ser cadastrado
     * @return - @true se o objeto foi cadastrado, @false se o objeto nao foi
     * cadastrado
     */
    public static boolean cadastrar(Object obj) {
        try {

            inicializaSessao();
            transacao = sessao.beginTransaction();
            sessao.merge(obj);
            transacao.commit();

            return true;

        } catch (HibernateException er) {

            er.printStackTrace();
            transacao.rollback();

            return false;

        } finally {

            fechaSessao();

        }
    }

    /**
     * Altera um unico objeto no banco de dados
     *
     * @param obj - Objetto a ser alterado
     * @return - @true se o objeto foi alterado, @false se o objeto nao foi
     * alterado
     */
    public static boolean alterar(Object obj) {
        try {

            inicializaSessao();
            transacao = sessao.beginTransaction();
            sessao.merge(obj);
            transacao.commit();

            return true;

        } catch (HibernateException er) {

            er.printStackTrace();
            transacao.rollback();

            return false;

        } finally {
            fechaSessao();

        }
    }

    /**
     * Exclui um unico objeto no banco de dados
     *
     * @param obj - Objeto a ser excluido
     * @return - @true se o objeto foi excluido, @false se o objeto nao foi
     * excluido
     */
    public static boolean excluir(Object obj) {
        try {

            inicializaSessao();
            transacao = sessao.beginTransaction();
            sessao.delete(obj);
            transacao.commit();

            return true;

        } catch (HibernateException er) {

            er.printStackTrace();
            transacao.rollback();
            return false;

        } finally {
            fechaSessao();
        }
    }

    /**
     * Esclui um determinado objeto a partir unicamente do seu id
     *
     * @param nomeObjeto
     * @param nomeId
     * @param id
     * @return
     */
    public static boolean excluirPorId(String nomeObjeto, String nomeId, Integer id) {

        try {

            List obj = consultar(nomeObjeto, "" + nomeId + "=" + id);
            Object objeto = obj.get(0);
            if (!excluir(objeto)) {
                System.out.println("Não foi possível excluir o objeto " + nomeObjeto + " de Id " + id);
            }

            return true;

        } catch (IndexOutOfBoundsException er) {

            return true;

        } catch (Exception er) {

            er.printStackTrace();
            return false;

        }

    }

    /**
     * Consulta todos as instancias de um determinado objeto
     *
     * @param nomeObjeto - Nome dos objetos a serem consultados no banco de
     * dados
     * @return - Lista preenchida com as instancias do objeto no banco de dados,
     * @null caso exista alguma excecao
     */
    public static List listar(String nomeObjeto) {
        try {

            inicializaSessao();
            transacao = sessao.beginTransaction();
            List list = sessao.createQuery("from " + nomeObjeto).list();

            return list;

        } catch (QueryException ex){
            JOptionPane.showMessageDialog(null, "Erro ao consultar Banco de Dados!\n"
                    + "Provavelmente a consulta tem algum caractere especial, como por exemplos aspas.\n"
                    + "Remova estes caracteres para prosseguir com a consulta.",
                    "Erro na consulta!", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
            return null;
            
        } catch (HibernateException er) {

            er.printStackTrace();
            return null;

        } finally {

            fechaSessao();
        }
    }

    /**
     * Consulta um tipo de objetos do banco de dados a partir de uma determinada
     * condicao
     *
     * @param nomeObjeto - Nome dos objetos a serem consultados no banco de
     * dados
     * @param condicao - Condicao a ser satisfeita para realizar a consulta
     * @return - Lista preenchida com os objetos que satisfazem a condicao
     */
    public static List consultar(String nomeObjeto, String condicao) {

        try {
            inicializaSessao();
            transacao = sessao.beginTransaction();
            List list = sessao.createQuery("from " + nomeObjeto + " where " + condicao).list();

            return list;

        } catch (QueryException ex){
            JOptionPane.showMessageDialog(null, "Erro ao consultar Banco de Dados!\n"
                    + "Provavelmente a consulta tem algum caractere especial, como por exemplos aspas.\n"
                    + "Remova estes caracteres para prosseguir com a consulta.",
                    "Erro na consulta!", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
            return null;
            
        } catch (Exception er) {

            er.printStackTrace();
            return null;

        } finally {
            fechaSessao();
        }
    }

    /**
     * Realiza uma consulta puramente através do HQL
     *
     * @return
     */
    public static List consultar(String hql) {

        try {
            inicializaSessao();
            transacao = sessao.beginTransaction();
            List list = sessao.createQuery(hql).list();

            return list;

        }  catch (QueryException ex){
            JOptionPane.showMessageDialog(null, "Erro ao consultar Banco de Dados!\n"
                    + "Provavelmente a consulta tem algum caractere especial, como por exemplos aspas.\n"
                    + "Remova estes caracteres para prosseguir com a consulta.",
                    "Erro na consulta!", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
            return null;
            
        } catch (Exception er) {

            er.printStackTrace();
            return null;

        } finally {
            fechaSessao();
        }
    }

    /**
     * Realiza uma listagem sem fechar a sessao
     *
     * @param nomeObjeto
     * @return
     */
    public static List listarSemFecharSessao(String nomeObjeto) {

        try {

            inicializaSessao();
            transacao = sessao.beginTransaction();
            List list = sessao.createQuery("from " + nomeObjeto).list();

            return list;

        }  catch (QueryException ex){
            JOptionPane.showMessageDialog(null, "Erro ao consultar Banco de Dados!\n"
                    + "Provavelmente a consulta tem algum caractere especial, como por exemplos aspas.\n"
                    + "Remova estes caracteres para prosseguir com a consulta.",
                    "Erro na consulta!", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
            return null;
            
        } catch (Exception er) {

            er.printStackTrace();
            return null;

        }
    }

    /**
     * Realiza uma consulta sem fechar a sessao
     *
     * @param nomeObjeto
     * @param condicao
     * @return
     */
    public static List consultarSemFecharSessao(String nomeObjeto, String condicao) {

        try {
            
            List list = null;
            inicializaSessao();
            transacao = sessao.beginTransaction();
            if (nomeObjeto != null) {
                list = sessao.createQuery("from " + nomeObjeto + " where " + condicao).list();
            } else {
                list = sessao.createQuery(condicao).list();
            }

            return list;

        }  catch (QueryException ex){
            JOptionPane.showMessageDialog(null, "Erro ao consultar Banco de Dados!\n"
                    + "Provavelmente a consulta tem algum caractere especial, como por exemplos aspas.\n"
                    + "Remova estes caracteres para prosseguir com a consulta.",
                    "Erro na consulta!", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
            return null;
            
        } catch (Exception er) {

            er.printStackTrace();
            return null;

        }
    }

    /**
     * Realiza a contagem de objetos na tabela
     *
     * @param nomeObjeto
     * @return
     */
    public static int count(Class classe) {
        try {
            inicializaSessao();
            Criteria criteria = sessao.createCriteria(classe);
            criteria.setProjection(Projections.rowCount());

            return ((Integer) criteria.list().get(0)).intValue();

        } catch (Exception er) {
            er.printStackTrace();
            transacao.rollback();
            return -1;

        } finally {

            sessao.flush();
            sessao.close();

        }
    }

    /**
     * Verifica qual o maior valor do atributo da classe no bd
     *
     * @param nomeObjeto
     * @return
     */
    public static int max(Class classe, String atributo) {
        try {
            inicializaSessao();
            Criteria criteria = sessao.createCriteria(classe);
            criteria.setProjection(Projections.max(atributo));

            if (((Integer) criteria.list().get(0)) != null) {
                return ((Integer) criteria.list().get(0)).intValue();
            } else {
                return 1;
            }



        } catch (Exception er) {
            er.printStackTrace();
            transacao.rollback();
            return -1;

        } finally {

            sessao.flush();
            sessao.close();

        }
    }

    public static Session getSession() {
        return sessao;
    }
}
